package viewbuilder

import org.junit.Test

import static org.junit.Assert.assertEquals
import org.junit.Before


class HtmlBuilderTest {

    StringWriter writer
    HtmlBuilder builder


    @Before
    public void initBuilder() {
        writer = new StringWriter()
        builder = new HtmlBuilder(writer)        
    }

    @Test
    public void validXmlCanbeConstructed() {
        builder.html {
            head {
                title("Foo Title")
            }
            body (id: 'mainBody') {
                p("Foo text")
            }
        }

        def html = new XmlSlurper().parseText(writer.toString())
        assertEquals("Foo Title", html.head.title.text())
        assertEquals("mainBody", html.body.@id.text())
        assertEquals("Foo text", html.body.p.text())
    }

    @Test
    public void textCanBeASiblingOfOtherChildElements() {

        builder.html {
            head {
                title("Foo Title")
            }
            body (id: 'mainBody') {
                text("Some text before")
                p("Foo text")
                text("Some text after")
            }
        }

        def html = new XmlSlurper().parseText(writer.toString())
        assertEquals("""
Some text before
Foo text
Some text after
""", html.body.text())

        assertEquals(0, html.body.text.size())

    }

    @Test
    public void firstChildElementMustAlwaysCloseAnOpenParentElement() {
        builder.state = HtmlBuilder.OPENED_ELEMENT
        builder.div(id:'monkey', 'foo the bar')
        assertEquals(">", writer.toString()[0])

        initBuilder()

        builder.state = HtmlBuilder.OPENED_ELEMENT
        builder.text('foo the bar')
        assertEquals(">", writer.toString()[0])
    }

    @Test
    public void creatingATextNodeWillSetTheStateToTextElement() {
        builder.state = HtmlBuilder.OPENED_ELEMENT
        builder.createNode("text", "Foo the bar")
        assertEquals(HtmlBuilder.TEXT_ELEMENT, builder.state)
    }

    @Test
    public void anyNonTextElementWithAValueWillCloseTheElement() {
        builder.state = HtmlBuilder.OPENED_ELEMENT
        builder.createNode("div", "With Some Value")
        assertEquals(HtmlBuilder.CLOSED_ELEMENT, builder.state)
    }

    @Test
    public void givingANodeAValueAndChildrenWillWriteTheValueAsTextFirstThenTheChildren() {
        builder.div("value") {
            p("child")
        }
        assertEquals("<div>value<p>child</p>\n</div>\n", writer.toString())
    }

    @Test
    public void emptyElementsAsChildrenAreClosedAtTheSameTimeAsTheyAreOpened() {
        builder.state = HtmlBuilder.CLOSED_ELEMENT
        builder.createNode("br")
        builder.setParent("div", "br")
        builder.nodeCompleted("div", "br")
        assertEquals("<br/>\n", writer.toString())
    }

    @Test
    public void emptyElementsAsSiblingAreClosedAtTheSameTimeAsTheyAreOpened() {
        builder.state = HtmlBuilder.CLOSED_ELEMENT
        builder.createNode("br")
        builder.setParent("div", "br")
        builder.nodeCompleted("div", "br")
        assertEquals("<br/>\n", writer.toString())
    }

    @Test
    public void nodeCompleteMustAllwaysLeaveTheSateAsClosedElement() {
        builder.state = HtmlBuilder.OPENED_ELEMENT
        builder.nodeCompleted("div", "span")
        assertEquals(HtmlBuilder.CLOSED_ELEMENT, builder.state)

        builder.state = HtmlBuilder.CLOSED_ELEMENT
        builder.nodeCompleted("div", "span")
        assertEquals(HtmlBuilder.CLOSED_ELEMENT, builder.state)

        builder.state = HtmlBuilder.TEXT_ELEMENT
        builder.nodeCompleted("div", "span")
        assertEquals(HtmlBuilder.CLOSED_ELEMENT, builder.state)
    }

    @Test
    public void completingAClosedElementMeansTheCurrentElementHasChildren() {
        builder.state = HtmlBuilder.CLOSED_ELEMENT
        builder.nodeCompleted ("div", "span")
        assertEquals("</span>\n", writer.toString())
    }

    @Test
    public void completingAnOpenElementMeansTheCurrentElementHasNoChildren() {
        builder.state = HtmlBuilder.OPENED_ELEMENT
        builder.nodeCompleted ("div", "br")
        assertEquals("/>\n", writer.toString())
    }

    @Test
    public void completingATextElementMeansThereIsNoXmlElementToClose() {
        builder.state = HtmlBuilder.TEXT_ELEMENT
        builder.nodeCompleted ("div", "text")
        assertEquals("\n", writer.toString())
    }

}